home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / asm / valarrow.zip / TED1.ASM < prev    next >
Assembly Source File  |  1994-03-02  |  56KB  |  1,962 lines

  1. ;======================================================================
  2. ;  TED.ASM -- The Tiny EDitor.
  3. ;  PC Magazine * Tom Kihlken * tktktk
  4. ;----------------------------------------------------------------------
  5. CSEG        SEGMENT
  6.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  7.         ORG    100H        ;Beginning for .COM programs
  8. START:
  9.         JMP    BEGIN
  10.  
  11. ;-----------------------------------------------------------------------
  12. ; Local data area
  13. ;-----------------------------------------------------------------------
  14. TAB        EQU    9
  15. CR        EQU    13
  16. LF        EQU    10
  17. LFCR        EQU    0A0DH
  18.  
  19. COPYRIGHT    DB    CR,LF,"TED 1.0 (c) 1988 Ziff Communications Co."
  20.         DB    CR,LF,"PC Magazine ",254," Tom Kihlken$",1AH
  21.  
  22. FILE_TOO_BIG    DB    "File too big$"
  23. READ_ERR_MESS    DB    "Read error$"
  24. MEMORY_ERROR    DB    "Not enough memory$"
  25.  
  26. PROMPT_STRING    DB    "1ABORT",0,"2CUT",0,"3PRINT",0
  27.         DB    "4MARK",0,"5COPY",0,"6PASTE",0,"7EXIT",0
  28.         DB    "8FIND ",0,"9DEL L",0,"10UDEL L",0,0
  29. PROMPT_LENGTH    =    $ - OFFSET PROMPT_STRING
  30.  
  31. VERIFY_MESS    DB    "Lose Changes (Y/N)?",0
  32. ESAVE_MESS    DB    "E-Save as: ",0
  33. SAVE_MESS    DB    " Save to : ",0
  34. COPY_MESS    DB    " Copy to : ",0
  35. OPEN_MESS    DB    "Open New : ",0
  36. MERGE_MESS    DB    "Merge in : ",0
  37. DOT_$$$        DB    ".$$$",0
  38. DOT_BAK        DB    ".BAK",0
  39. REPL_PROMPT2    DB      "REPLACE STRING (Y/N) ",0
  40. REPL_PROMPT     DB      "REPLACE STRING> ",0
  41. REPL_MAX    DB    66
  42. REPL_SIZ    DB    0
  43. REPL_STR        DB      66 DUP (0)
  44. SRCH_PROMPT     DB      "SEARCH STRING> ",0
  45. SRCH_MAX    DB    66
  46. SRCH_SIZ    DB    0
  47. SRCH_STR        DB      66 DUP (0)
  48. SRCH_FLG    DB    0
  49. SRCH_END    DW    0
  50. SRCH_BASE    DW    0
  51. SRCH_CLR    DB    244
  52. KP_CR        DB    0
  53. DIRTY_BITS    DB    1
  54. ORGATR      DB    0
  55. NORMAL        DB    17h
  56. INVERSE        DB    70h
  57. LEFT_MARGIN    DB    0
  58. MARGIN_COUNT    DB    0
  59. INSERT_MODE    DB    -1
  60. MARK_MODE    DB    0
  61. EXIT_MODE    DB    0
  62. ROWS        DB    23
  63. SAVE_COLUMN    DB    0
  64. SAVE_ROW    DB    0
  65. LINE_FLAG    DB    0
  66. MERGE_NAME        DB    60 DUP(0)
  67. EVEN
  68. P_MERGE_NAME    DW    [MERGE_NAME]
  69. P_FNAME        DW    0
  70. P_FNAME_END    DW    0
  71. P_FNAME_PROMPT    DW    0
  72. FNAME_LIMIT    DW    0
  73. NAME_POINTER    DW    81H
  74. NAME_END    DW    81H
  75. STATUS_REG    DW    ?
  76. VIDEO_SEG    DW    0B000H
  77. LINE_LENGTH    DW    0
  78. UNDO_LENGTH    DW    0
  79. CUR_POSN    DW    0
  80. MARK_START    DW    0FFFFH
  81. MARK_END    DW    0
  82. MARK_HOME    DW    0
  83. TOP_OF_SCREEN    DW    0
  84. CURSOR        DW    0
  85. LAST_CHAR    DW    0
  86. COLUMNSB    LABEL    BYTE
  87. COLUMNS        DW    ?
  88. FL_SEG        DW    ?
  89. PASTE_SEG    DW    ?
  90. PASTE_SIZE    DW    0
  91. PAGE_PROC    DW    ?
  92. OLDINT24    DD    ?
  93. DISPATCH_TABLE    DW    OFFSET ABORT   ,OFFSET CUT    ,OFFSET PRINT
  94.         DW    OFFSET MARK    ,OFFSET COPY   ,OFFSET PASTE
  95.         DW    OFFSET EXIT    ,OFFSET FIND_STR,OFFSET DEL_L
  96.         DW    OFFSET UDEL_L  ,OFFSET BAD_KEY,OFFSET BAD_KEY
  97.         DW    OFFSET HOME    ,OFFSET UP     ,OFFSET PGUP
  98.         DW    OFFSET BAD_KEY ,OFFSET LEFT   ,OFFSET BAD_KEY
  99.         DW    OFFSET RIGHT   ,OFFSET BAD_KEY,OFFSET ENDD
  100.         DW    OFFSET DOWN    ,OFFSET PGDN   ,OFFSET INSERT
  101. DSP83        DW    OFFSET DEL_CHAR
  102. SHIFT_F1_84    DW    OFFSET BAD_KEY, OFFSET BAD_KEY, OFFSET BAD_KEY
  103.     DW OFFSET BAD_KEY, OFFSET BAD_KEY, OFFSET BAD_KEY, OFFSET BAD_KEY
  104.     DW OFFSET FIND_STR, OFFSET BAD_KEY, OFFSET BAD_KEY
  105. CTRL_F1_94    DW    OFFSET OPEN_NEW, OFFSET ABORT, OFFSET BAD_KEY
  106.     DW OFFSET BAD_KEY, OFFSET EXIT, OFFSET MERGE, OFFSET EXIT
  107.     DW OFFSET FIND_STR, OFFSET BAD_KEY, OFFSET BAD_KEY
  108.  
  109. ; The following machine instruction removes the desnow delay.  It is
  110. ; inserted into the code for EGA, VGA, and MONO displays.
  111.  
  112. NO_DESNOW = 0EBH + (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256
  113.  
  114. ;-----------------------------------------------------------------------
  115. ; We start by initialize the display, then allocate memory for the file
  116. ; and paste segments.  Parse the command line for a filename, if one was
  117. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  118. ;-----------------------------------------------------------------------
  119. BEGIN:
  120.         MOV    AX,3
  121.         INT    10h
  122.         XOR    AX,AX
  123.         MOV    DS,AX        ;Get a zero into DS
  124.         ASSUME    DS:NOTHING
  125.         MOV    AH,12H
  126.         MOV    BL,10H        ;Get EGA info
  127.         INT    10H
  128.         CMP    BL,10H        ;Did BL change?
  129.         JE    NOT_EGA        ;If not, no EGA in system
  130.         TEST    BYTE PTR DS:[0487H],8    ;Is EGA active?
  131.         JNZ    NOT_EGA
  132.         MOV    WORD PTR CS:HWAIT,NO_DESNOW ;Get rid of desnow
  133.         MOV    AX,DS:[0484H]    ;Get number of rows
  134.         DEC    AL        ;Last row is for prompt line
  135.          MOV    CS:[ROWS],AL    ;Save the number of rows
  136. NOT_EGA:
  137.         MOV    AX,DS:[044AH]    ;Get number of columns
  138.         MOV    CS:COLUMNS,AX    ;and store it
  139.         MOV    AX,DS:[0463H]    ;Address of display card
  140.         ADD    AX,6        ;Add six to get status port
  141.         PUSH    CS
  142.         POP    DS
  143.         ASSUME    DS:CSEG
  144.         MOV    STATUS_REG,AX
  145.         CMP    AX,3BAH        ;Is this a MONO display?
  146.         JNE    COLOR        ;If not, must be a CGA
  147.         MOV    WORD PTR HWAIT,NO_DESNOW ;Get rid of desnow
  148.         JMP    SHORT MOVE_STACK
  149. COLOR:
  150.         MOV    VIDEO_SEG,0B800H;Segment for color card
  151.         XOR    BH,BH        ;Use page zero
  152.         MOV    AH,8        ;Get current attribute
  153.         INT    10H
  154.         MOV    ORGATR,AH    ;Save the original attribute
  155. MOVE_STACK:
  156.         MOV    BX,OFFSET NEW_STACK
  157.         MOV    SP,BX        ;Move the stack downward
  158.         ADD    BX,15
  159.         MOV    CL,4        ;Convert program size to
  160.         SHR    BX,CL        ; paragraphs
  161.         MOV    AH,4AH        ;Deallocate unused memory
  162.         INT    21H
  163.         MOV    BX,1000H    ;Request 64K for file segment
  164.         MOV    AH,48H
  165.         INT    21H
  166.         MOV    ES,AX
  167.         MOV    FL_SEG,AX
  168.         ASSUME    ES:FILE_SEG
  169.         MOV    AH,48H
  170.         INT    21H        ;Request 64K for paste buffer
  171.         JNC    GOT_ENOUGH    ;If enough memory, continue
  172. NOT_ENOUGH:
  173.         MOV    DX,OFFSET MEMORY_ERROR
  174. ERR_EXIT:
  175.         PUSH    CS
  176.         POP    DS
  177.         MOV    AH,9        ;Write the error message
  178.         INT    21H        ;DOS display service
  179.         JMP    EXIT_TO_DOS    ;Exit this program
  180. GOT_ENOUGH:
  181.         MOV    PASTE_SEG,AX    ;Use this for the paste buffer
  182. GET_FILENAME:
  183.         MOV    SI,80H        ;Point to parameters
  184.         MOV    CL,[SI]        ;Get number of characters
  185.         XOR    CH,CH        ;Make it a word
  186.         INC    SI        ;Point to first character
  187.         PUSH    SI
  188.         ADD    SI,CX        ;Point to last character
  189.         MOV    BYTE PTR [SI],0    ;Make it an ASCII string
  190.         MOV    NAME_END,SI    ;Save pointer to last character
  191.         POP    SI        ;Get back pointer to filename
  192.         CLD
  193.         JCXZ    NO_FILENAME    ;If no params, just exit
  194. DEL_SPACES:    LODSB            ;Get character into AL
  195.         CMP    AL," "        ;Is it a space?
  196.         JNE    FOUND_LETTER
  197.         LOOP    DEL_SPACES
  198. FOUND_LETTER:
  199.         DEC    SI        ;Backup pointer to first letter
  200.         MOV    NAME_POINTER,SI    ;Save pointer to filename
  201.         MOV    DX,SI
  202. OPEN_FILE:
  203.         MOV    AX,3D00H    ;Setup to open file
  204.         INT    21H
  205.         JC    NO_FILENAME     ;If we can't open, must be new file
  206. FILE_OPENED:
  207.         PUSH    ES
  208.         POP    DS        ;DS has file segment also
  209.         ASSUME    DS:FILE_SEG
  210.         MOV    BX,AX        ;Get the handle into BX
  211.         XOR    DX,DX        ;Point to file buffer
  212.         MOV    AH,3FH        ;Read service
  213.         MOV    CX,0FFFEH    ;Read almost 64K bytes
  214.         INT    21H
  215.         MOV    DI,AX        ;Number of bytes read in
  216.         JNC    NO_RD_ERR    ;If no error, take jump
  217.         MOV    DX,OFFSET READ_ERR_MESS
  218.         JMP    SHORT ERR_EXIT
  219. NO_RD_ERR:
  220.         MOV    LAST_CHAR,DI    ;Save the file size
  221.         CMP    CX,AX        ;Did the buffer fill?
  222.         MOV    DX,OFFSET FILE_TOO_BIG
  223.         JE    ERR_EXIT    ;If yes, it is too big
  224.         MOV    AH,3EH
  225.         INT    21H        ;Close the file
  226. NO_FILENAME:
  227.         PUSH    ES
  228.         PUSH    ES        ;Save file segment
  229.         MOV    AX,3524H    ;Get INT 24 vector
  230.         INT    21H
  231.         MOV    WORD PTR OLDINT24,BX  ;Store the offset
  232.         MOV    WORD PTR OLDINT24+2,ES;And the segment
  233.  
  234.         PUSH    CS
  235.         POP    DS
  236.         MOV    DX,OFFSET NEWINT24    ;Point to new vector
  237.         MOV    AX,2524H    ;Now change INT 24 vector
  238.         INT    21H    
  239.  
  240.         MOV    DX,OFFSET NEWINT23
  241.         MOV    AX,2523H    ;Set the INT 23 vector also
  242.         INT    21H
  243.  
  244.         POP    ES        ;Get back file segment
  245.         POP    DS
  246.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  247.         CALL    TOP
  248.         CALL    REDO_PROMPT    ;Draw the prompt line
  249.  
  250. ;-----------------------------------------------------------------------
  251. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  252. ;-----------------------------------------------------------------------
  253. READ_A_KEY:
  254.         CMP    MARK_MODE,0    ;Is the mark state on?
  255.         JE    MARK_OFF    ;If not, skip this
  256.         OR    DIRTY_BITS,4    ;Refresh the current row
  257.         MOV    DX,CUR_POSN
  258.         CMP    SAVE_ROW,DH    ;Are we on the save row?
  259.         JE    SAME_ROW    ;If yes, then redo the row only
  260.         MOV    DIRTY_BITS,1    ;Refresh the whole screen
  261. SAME_ROW:
  262.         MOV    AX,CURSOR    ;Get cursor location
  263.         MOV    BX,MARK_HOME    ;Get the anchor mark position
  264.         CMP    AX,BX        ;Moving backward in file?
  265.         JAE    S1
  266.         MOV    MARK_START,AX    ;Switch start and end position
  267.         MOV    MARK_END,BX
  268.         JMP    SHORT MARK_OFF
  269. S1:
  270.         MOV    MARK_END,AX    ;Store start and end marks
  271.         MOV    MARK_START,BX
  272. MARK_OFF:
  273.         MOV    DX,CUR_POSN
  274.         MOV    SAVE_ROW,DH
  275.         CALL    SET_CURSOR    ;Position the cursor
  276.         TEST    DIRTY_BITS,1    ;Look at screen dirty bit
  277.         JZ    SCREEN_OK    ;If zero, screen is OK
  278.  
  279.         MOV    AH,1        ;Get keyboard status
  280.         INT    16H        ;Any keys ready?
  281.         JNZ    CURRENT_OK    ;If yes, skip the update
  282.         CALL    DISPLAY_SCREEN    ;Redraw the screen
  283.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  284. SCREEN_OK:
  285.         TEST    DIRTY_BITS,4    ;Is the current line dirty?
  286.         JZ    CURRENT_OK    ;If not, take jump
  287.         CALL    DISPLAY_CURRENT    ;Redraw the current line
  288.         MOV    DIRTY_BITS,0    ;Mark screen as OK
  289. CURRENT_OK:
  290.         MOV    KP_CR,0
  291.         MOV    AH,10H        ;Read the next key
  292.         INT    16H
  293.         CMP    SRCH_FLG,0
  294.         JE    CKEXT
  295.         MOV    SRCH_FLG,0
  296.         MOV    DIRTY_BITS,1
  297. CKEXT:        CMP    AL,0        ;Is this an extended code?
  298.         JE    EXTENDED_CODE
  299.         CMP    AL,0E0H        ;Is this an extended code?
  300.         JNE    DO_BAD
  301.         CMP    AH,0
  302.         JNE    EXTENDED_CODE
  303. DO_BAD:
  304.         CMP    AH,0EH        ;Was it the backspace key?
  305.         JE    BACK_SPACE
  306.         CALL    INSERT_KEY    ;Put this character in the file
  307.         JMP    READ_A_KEY    ;Get another key
  308. BACK_SPACE:
  309.         CMP    CURSOR,0    ;At start of file?
  310.         JE    BACK_END    ;If at start, can't backspace
  311.         CALL    LEFT        ;Move left one space
  312.         CALL    DEL_CHAR    ;And delete the character
  313. BACK_END:    JMP    READ_A_KEY
  314. EXTENDED_CODE:
  315.         MOV    AL,0
  316.         CMP    AH,84H        ;Is it control PgUp?
  317.         JNE    NOT_TOP
  318.         CALL    TOP
  319.         JMP    READ_A_KEY
  320. NOT_TOP:
  321.         CMP    AH,76H        ;Is it control PgDn?
  322.         JNE    NOT_BOTTOM
  323.         CALL    BOTTOM
  324.         JMP    READ_A_KEY
  325. BAD_KEY:
  326.         MOV    AL,AH
  327.         JMP    SHORT DO_BAD
  328. NOT_BOTTOM:
  329.         CMP    AH,73H        ;Is it control left arrow?
  330.         JE    SH_LEFT
  331.         CMP    AH,74H        ;Is it control right arrow?
  332.         JE    SH_RIGHT
  333.         CMP    AH,103        ;Skip high numbered keys (67h)
  334.         JA    BAD_KEY
  335.         mov    CH,AH
  336.         XCHG    AH,AL
  337.         SUB    AL,3BH        ;Also skip low numbered keys
  338.         JC    BAD_KEY
  339.         SHL    AX,1        ;Make the code an offset
  340.         MOV    BX,AX        ;Put offset in BX
  341.         CALL    CS:DISPATCH_TABLE[BX] ;Call the key procedure
  342.         JMP    READ_A_KEY    ;Then read another key
  343.  
  344. ;-----------------------------------------------------------------------
  345. ; These two routines shift the display right or left to allow editing
  346. ; files which contain lines longer than 80 columns.
  347. ;-----------------------------------------------------------------------
  348. SH_RIGHT    PROC    NEAR
  349.         CMP    LEFT_MARGIN,255 - 8 ;Past max allowable margin?
  350.         JAE    NO_SHIFT    ;Then can't move any more
  351.         ADD    LEFT_MARGIN,8    ;This moves the margin over
  352. SH_RETURN:
  353.         CALL    CURSOR_COL    ;Compute column for cursor
  354.         MOV    DX,CUR_POSN
  355.         MOV    SAVE_COLUMN,DL    ;Save the current column
  356.         MOV    DIRTY_BITS,1    ;Redraw the screen
  357. NO_SHIFT:
  358.         JMP    READ_A_KEY
  359. SH_RIGHT    ENDP
  360.  
  361. SH_LEFT        PROC    NEAR
  362.         CMP    LEFT_MARGIN,0    ;At start of line already?
  363.         JE    NO_SHIFT    ;If yes, then don't shift
  364.         SUB    LEFT_MARGIN,8    ;Move the window over
  365.         JMP    SH_RETURN
  366. SH_LEFT        ENDP
  367.  
  368. ;-----------------------------------------------------------------------
  369. ; This moves the cursor to the top of the file.
  370. ;-----------------------------------------------------------------------
  371. TOP        PROC    NEAR
  372.         XOR    AX,AX        ;Get a zero into AX
  373.         MOV    CURSOR,AX    ;Cursor to start of file
  374.         MOV    TOP_OF_SCREEN,AX
  375.         MOV    LEFT_MARGIN,AL    ;Move to far left margin
  376.         MOV    DIRTY_BITS,1    ;Redraw the screen
  377.         MOV    CUR_POSN,AX    ;Home the cursor
  378.         MOV    SAVE_COLUMN,AL    ;Save the cursor column
  379.         RET
  380. TOP        ENDP
  381.  
  382. ;-----------------------------------------------------------------------
  383. ; This moves the cursor to the bottom of the file
  384. ;-----------------------------------------------------------------------
  385. BOTTOM        PROC    NEAR
  386.         MOV    DH,ROWS        ;Get screen size
  387.         MOV    SI,LAST_CHAR    ;Point to last character
  388.         DEC    SI
  389.         MOV    LEFT_MARGIN,0    ;Set window to start of line
  390.         CALL    LOCATE        ;Adjust the screen position
  391.         CALL    HOME        ;Move cursor to start of line
  392.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  393.         RET
  394. BOTTOM        ENDP
  395.  
  396. ;-----------------------------------------------------------------------
  397. OPEN_NEW    PROC    NEAR
  398.         PUSH    CS
  399.         POP    DS
  400.         MOV    AX,NAME_POINTER
  401.         MOV    SI,OFFSET OPEN_MESS
  402.         CALL    FILENAME
  403.         MOV    ES,FL_SEG
  404.         MOV    DIRTY_BITS,1    ;Redraw the screen
  405.  
  406.         CMP    AL,27        ;Is it escape?
  407.         JNE    OPEN_NOT_ESCAPE
  408.         CALL    REDO_PROMPT    ;Redraw the prompt
  409.         PUSH    ES
  410.         POP    DS
  411.         RET
  412. OPEN_NOT_ESCAPE:
  413.         MOV    DX,NAME_POINTER
  414.         JMP    OPEN_FILE
  415. OPEN_NEW    ENDP
  416.  
  417. ;-----------------------------------------------------------------------
  418. ; Merge in a second file at cursor location
  419. ;-----------------------------------------------------------------------
  420. MERGE        PROC    NEAR
  421.         PUSH    DS
  422.         PUSH    ES
  423.  
  424.         PUSH    CS        ;MOV CS to DS
  425.         POP    DS
  426.         MOV    AX,P_MERGE_NAME
  427.         MOV    SI,OFFSET MERGE_MESS
  428.         CALL    FILENAME
  429.         CMP    AL,27        ;Is it escape?
  430.         JE    ESCAPE_MERGE
  431.         MOV    DX,P_MERGE_NAME
  432.         MOV    AX,3D00H    ;Setup to open file
  433.         INT    21H
  434.         JC    MERGE_ERR     ;can't open file
  435.         MOV    DS,PASTE_SEG
  436.         MOV    BX,AX        ;Get the handle into BX
  437.         XOR    DX,DX        ;Point to file buffer
  438.         MOV    AH,3FH        ;Read service
  439.         MOV    CX,0FFFEH    ;Read almost 64K bytes
  440.         INT    21H
  441.         MOV    DI,AX        ;Number of bytes read in
  442.         JC    MERGE_ERR    ;Error reported
  443.         MOV    PASTE_SIZE,DI    ;Save the file size
  444.         CMP    CX,AX        ;Did the buffer fill?
  445.         JE    MERGE_ERR    ;If yes, it is too big
  446.         MOV    AH,3EH
  447.         INT    21H        ;Close the file
  448.         POP    ES
  449.         POP    DS
  450.         CALL    PASTE
  451.         MOV    PASTE_SIZE,0
  452.         MOV    DIRTY_BITS,1    ;Redraw the screen
  453.         CALL    REDO_PROMPT    ;Redraw the prompt
  454.         RET
  455. MERGE_ERR:
  456.         MOV    AX,0E07H    ;Write a bell character
  457.         INT    10H        ;BIOS tty service
  458.         POP    ES
  459.         POP    DS
  460.         MOV    DIRTY_BITS,1    ;Redraw the screen
  461.         CALL    REDO_PROMPT    ;Redraw the prompt
  462.         RET
  463. ESCAPE_MERGE:
  464.         POP    ES
  465.         POP    DS
  466.         MOV    DIRTY_BITS,1    ;Redraw the screen
  467.         CALL    REDO_PROMPT    ;Redraw the prompt
  468.         RET
  469.  
  470. MERGE        ENDP
  471.  
  472. ;-----------------------------------------------------------------------
  473. ; Search for a string
  474. ;-----------------------------------------------------------------------
  475. FIND_STR    PROC    NEAR
  476.         PUSH    DS
  477.         MOV    BX,CS
  478.         MOV    DS,BX
  479.         CMP    CH,101        ;Is it CTRL F8
  480.         JE    RPT_FIND
  481.         MOV    REPL_SIZ,255
  482.         PUSH    CX
  483.         MOV    DH,ROWS
  484.         INC    DH        ;Last row on the screen
  485.         XOR    DL,DL        ;First column
  486.         MOV    SI,OFFSET SRCH_PROMPT
  487.         CALL    TTY_STRING    ;Display search prompt
  488.         MOV    DX, OFFSET SRCH_MAX
  489.         MOV    AH,0Ah
  490.         INT    21h        ;Read input string
  491.         POP    CX
  492.  
  493.         CMP    CH,91        ;Is it SHIFT F8
  494.         JNE    RPT_FIND
  495.         MOV    DH,ROWS
  496.         INC    DH        ;Last row on the screen
  497.         XOR    DL,DL        ;First column
  498.         MOV    SI,OFFSET REPL_PROMPT
  499.         CALL    TTY_STRING    ;Display search prompt
  500.         MOV    DX, OFFSET REPL_MAX
  501.         MOV    AH,0Ah
  502.         INT    21h        ;Read input string
  503.  
  504. RPT_FIND:
  505.         XOR    DX,DX
  506.         MOV    DL, BYTE PTR SRCH_SIZ
  507.         ADD    DX, OFFSET SRCH_STR
  508.         MOV    DI,DX
  509.         DEC    DI
  510.         MOV    SRCH_END,DI
  511.         XOR    DX,DX
  512.         MOV    SI,CURSOR
  513.         INC    SI
  514.         MOV    SRCH_BASE,SI
  515. S_REDO:        MOV    DI,OFFSET SRCH_STR
  516.         MOV    BX,SRCH_BASE
  517. S_CYCLE:    MOV    AL,[DI]
  518.         MOV    AH,AL        ;CONVERT AL TO OPPOSITE AND PUT IN AH
  519.         CMP    AL,65
  520.         JB    S_CMP
  521.         CMP    AL,90
  522.         JA    TSTLO
  523.         XOR    AH,20H
  524.         JMP    SHORT S_CMP
  525. TSTLO:        CMP    AL,97
  526.         JB    S_CMP
  527.         XOR    AH,20H
  528. S_CMP:        CMP    BX,LAST_CHAR
  529.         JA    END_MCH
  530.         CMP    AL,ES:[BX]
  531.         JE    S_MCH
  532.         CMP    AH,ES:[BX]
  533.         JE    S_MCH
  534.         CMP    DI,OFFSET SRCH_STR
  535.         JNE    S_REDO
  536.         INC    BX
  537.         CMP    WORD PTR ES:[BX]-1,LFCR
  538.         JNE    S_BX1
  539.         INC    DL
  540. S_BX1:        JMP    SHORT S_CMP
  541. END_MCH:        
  542.         POP    DS
  543.         CALL    REDO_PROMPT
  544.         RET
  545.         
  546. S_MCH:        INC    BX
  547.         CMP    DI,OFFSET SRCH_STR
  548.         JNE    NO_BSE
  549.         MOV    SRCH_BASE,BX
  550. NO_BSE:        ADD    DH,DL
  551.         XOR    DL,DL
  552.         CMP    DI,SRCH_END
  553.         JE    YEA_MCH
  554.         INC    DI
  555.         JMP    SHORT S_CYCLE
  556. YEA_MCH:    
  557.         MOV    SRCH_FLG,1
  558.         MOV    SI,SRCH_BASE
  559.         DEC    SI
  560.         MOV    SRCH_BASE,SI
  561.         MOV    CURSOR,SI
  562.         XOR    BX,BX
  563.         MOV    BL,BYTE PTR SRCH_SIZ
  564.         ADD    BX,SI
  565.         MOV    SRCH_END,BX
  566.         XOR    DL,DL
  567.         ADD    DX,CUR_POSN
  568.         CMP    DH,ROWS
  569.         JBE    NEW_S
  570.         XOR    DX,DX
  571. NEW_S:        
  572.         POP    DS
  573.         CALL    LOCATE
  574.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  575.         CMP    REPL_SIZ,255
  576.         JNE    REPLACE_STR
  577.         CALL    REDO_PROMPT
  578.         RET
  579. REPLACE_STR:
  580.         CALL    DISPLAY_SCREEN
  581.         PUSH    DS
  582.         PUSH    CS
  583.         POP    DS
  584.         MOV    SRCH_FLG,0
  585.         MOV    DH,ROWS
  586.         INC    DH        ;Last row on the screen
  587.         XOR    DL,DL        ;First column
  588.         MOV    SI,OFFSET REPL_PROMPT2
  589.         CALL    TTY_STRING    ;Display search prompt
  590.         POP    DS
  591.         PUSH    DS
  592.         XOR    AH,AH        ;Read the next key
  593.         INT    16H        ;BIOS read key routine
  594.         OR    AL,32        ;Convert to lower case
  595.         CMP    AL,"y"        ;Was answer Yes?
  596.         JNE    REPLACE_END
  597.  
  598.  
  599.         XOR    AH,AH
  600.         MOV    AL,SRCH_SIZ
  601.         MOV    CX,LAST_CHAR    ;Get the file size
  602.         SUB    LAST_CHAR,AX    ;Subtract the deleted line
  603.         MOV    SI,CURSOR    ;Get new cursor location
  604.         MOV    DI,SI
  605.         ADD    SI,AX        ;SI points to end of file
  606.         SUB    CX,SI        ;Length of remaining file
  607.         JCXZ    REPLACE_INS
  608.         REP    MOVSB        ;Shift remainder of file up
  609. REPLACE_INS:
  610.  
  611.         XOR    AH,AH
  612.         MOV    AL,REPL_SIZ
  613.         MOV    SI,OFFSET REPL_STR
  614.         CALL    INSERT_STRING
  615.  
  616. REPLACE_END:    POP    DS
  617.         MOV    DIRTY_BITS,1    ;This will redraw the screen
  618.         CALL    REDO_PROMPT
  619.         RET
  620.  
  621. FIND_STR    ENDP
  622.  
  623. ;-----------------------------------------------------------------------
  624. ; This deletes from the cursor position to the end of line.
  625. ;-----------------------------------------------------------------------
  626. DEL_EOL        PROC    NEAR
  627.         MOV    CX,CUR_POSN
  628.         OR    CL,CL        ;At first column?
  629.         JZ    DEL_L        ;If yes, then do line delete function
  630.         MOV    LINE_FLAG,0
  631.         PUSH    CURSOR        ;Save starting cursor location
  632.         CALL    ENDD        ;Move the the end of line
  633.         POP    SI        ;Get back starting cursor
  634.         MOV    CX,CURSOR    ;Offset of the end of line
  635.         MOV    CURSOR,SI    ;Restore starting cursor
  636.         JMP    DEL_END        ;Delete characters to end
  637. DEL_EOL        ENDP
  638.  
  639.  
  640. ;-----------------------------------------------------------------------
  641. ; This deletes a line, placing it in the line buffer.
  642. ;-----------------------------------------------------------------------
  643. DEL_L        PROC    NEAR
  644.         MOV    LINE_FLAG,1
  645.         CALL    FIND_START    ;Find start of this line
  646.         MOV    CURSOR,SI    ;This will be the new cursor
  647.         PUSH    SI        ;Save the cursor position
  648.         CALL    FIND_NEXT    ;Find the next line
  649.         MOV    CX,SI        ;CX will hold line length
  650.         POP    SI        ;Get back new cursor location
  651. DEL_END:
  652.         SUB    CX,SI        ;Number of bytes on line
  653.         OR    CH,CH        ;Is line too long to fit
  654.         JZ    NOT_TOO_LONG
  655.         MOV    CX,100H        ;Only save 256 characters
  656. NOT_TOO_LONG:
  657.         MOV    LINE_LENGTH,CX    ;Store length of deleted line
  658.         JCXZ    NO_DEL_L
  659.         MOV    DI,OFFSET LINE_BUFFER ;Buffer for deleted line
  660.  
  661.         PUSH    CX
  662.         PUSH    ES
  663.         PUSH    CS
  664.         POP    ES        ;Line buffer is in CSEG
  665.         REP    MOVSB        ;Put deleted line in buffer
  666.         POP    ES        ;Get back file segment
  667.         POP    AX
  668.  
  669.         MOV    CX,LAST_CHAR    ;Get the file size
  670.         SUB    LAST_CHAR,AX    ;Subtract the deleted line
  671.         MOV    SI,CURSOR    ;Get new cursor location
  672.         MOV    DI,SI
  673.         ADD    SI,AX        ;SI points to end of file
  674.         SUB    CX,SI        ;Length of remaining file
  675.         JCXZ    NO_DEL_L
  676.         REP    MOVSB        ;Shift remainder of file up
  677. NO_DEL_L:
  678.         MOV    DX,CUR_POSN    ;Get cursor row/column
  679.         MOV    SI,CURSOR    ;Get cursor offset
  680.         CALL    LOCATE        ;Adjust the screen position
  681.         MOV    DIRTY_BITS,1    ;Redraw the screen
  682.         RET
  683. DEL_L        ENDP
  684.  
  685. ;-----------------------------------------------------------------------
  686. ; This undeletes a line by copying it from the line buffer into the file
  687. ;-----------------------------------------------------------------------
  688. UDEL_L        PROC    NEAR
  689.         CMP    LINE_FLAG,0    ;Is this an end of line only?
  690.         JE    UDEL_EOL    ;If yes, don't home the cursor
  691.         CALL    HOME        ;Move cursor to home
  692. UDEL_EOL:
  693.         MOV    AX,LINE_LENGTH    ;Length of deleted line
  694.         MOV    SI,OFFSET LINE_BUFFER
  695.         JMP    INSERT_STRING
  696. UDEL_L        ENDP
  697.  
  698. ;-----------------------------------------------------------------------
  699. ; These routines move the cursor left and right.
  700. ;-----------------------------------------------------------------------
  701. LEFT        PROC    NEAR
  702.         CMP    CURSOR,0    ;At start of file?
  703.         JZ    LR_NO_CHANGE    ;Then can't move left
  704.         MOV    DX,CUR_POSN
  705.         OR    DL,DL        ;At first column?
  706.         JZ    MOVE_UP        ;If yes, then move up one
  707.         DEC    CURSOR        ;Shift the cursor offset
  708. LR_RETURN:
  709.         CALL    CURSOR_COL    ;Compute column for cursor
  710.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  711. LR_NO_CHANGE:
  712.         MOV    UNDO_LENGTH,0
  713.         RET
  714. MOVE_UP:
  715.         CALL    UP        ;Move up to next row
  716.         JMP    SHORT ENDD    ;And move to end of line
  717. LEFT        ENDP
  718.  
  719. RIGHT        PROC    NEAR
  720.         MOV    SI,CURSOR
  721.         CMP    SI,LAST_CHAR    ;At end of file?
  722.         JE    LR_NO_CHANGE    ;If yes, then can't move
  723.         CMP    BYTE PTR [SI],CR;If CR
  724.         JNE    INC_RIGHT    ;If yes, then test LF
  725.         INC    SI
  726.         CMP    SI,LAST_CHAR    ;At end of file?
  727.         DEC    SI
  728.         JE    INC_RIGHT    ;If yes, then increment
  729.         CMP    BYTE PTR [SI+1],LF;If LF
  730.         JE    MOVE_DOWN    ;If yes, then move to next line
  731. INC_RIGHT:
  732.         INC    CURSOR        ;Advance the cursor
  733.         JMP    LR_RETURN
  734. MOVE_DOWN:
  735.         CALL    HOME        ;Move to start of line
  736.         JMP    DOWN        ;And move down one row
  737. RIGHT        ENDP
  738.  
  739. ;-----------------------------------------------------------------------
  740. ; This moves the cursor to the start of the current line.
  741. ;-----------------------------------------------------------------------
  742. HOME        PROC    NEAR
  743.         CALL    FIND_START    ;Find start of line
  744.         MOV    CURSOR,SI    ;Save the new cursor
  745.         MOV    SAVE_COLUMN,0    ;Save the cursor column
  746.         MOV    BYTE PTR CUR_POSN,0 ;Store column number
  747.         RET
  748. HOME        ENDP
  749.  
  750. ;-----------------------------------------------------------------------
  751. ; This moves the cursor to the end of the current line
  752. ;-----------------------------------------------------------------------
  753. ENDD        PROC    NEAR
  754.         MOV    SI,CURSOR
  755.         CALL    FIND_EOL    ;Find end of this line
  756.         MOV    CURSOR,SI    ;Store the new cursor
  757.         CALL    CURSOR_COL    ;Compute the correct column
  758.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  759.         RET
  760. ENDD        ENDP
  761.  
  762. ;-----------------------------------------------------------------------
  763. ; This moves the cursor up one row.  If the cursor is at the first row,
  764. ; the screen is scrolled down.
  765. ;-----------------------------------------------------------------------
  766. UP        PROC    NEAR
  767.         MOV    UNDO_LENGTH,0
  768.         MOV    DX,CUR_POSN
  769.         MOV    SI,CURSOR
  770.         OR    DH,DH        ;At top row already?
  771.         JZ    SCREEN_DN    ;If yes, then scroll down
  772.         DEC    DH        ;Move cursor up one row
  773.         CALL    FIND_CR        ;Find the beginning of this row
  774.         MOV    CURSOR,SI
  775.         CALL    FIND_START    ;Find start of this row
  776.         MOV    CURSOR,SI
  777.         CALL    SHIFT_RIGHT    ;Skip over to current column
  778. AT_TOP:
  779.         RET
  780. SCREEN_DN:
  781.         MOV    SI,TOP_OF_SCREEN
  782.         OR    SI,SI        ;At start of file?
  783.         JZ    AT_TOP        ;If at top, then do nothing
  784.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  785.         MOV    TOP_OF_SCREEN,SI;Save new top of screen
  786.         MOV    SI,CURSOR
  787.         CALL    FIND_PREVIOUS    ;Find the preceeding line
  788.         MOV    CURSOR,SI    ;This is the new cursor
  789. SHIFT_RET:
  790.         MOV    DIRTY_BITS,1    ;Need to redraw screen
  791.         MOV    SI,CURSOR
  792.         MOV    DX,CUR_POSN
  793.         JMP    SHIFT_RIGHT    ;Move cursor to current column
  794. UP        ENDP
  795.  
  796. ;-----------------------------------------------------------------------
  797. ; This moves the cursor down one row.  When the last row is reached,
  798. ; the screen is shifted up one row.
  799. ;-----------------------------------------------------------------------
  800. DOWN        PROC    NEAR
  801.         MOV    UNDO_LENGTH,0
  802.         MOV    DX,CUR_POSN
  803.         CMP    DH,ROWS        ;At bottom row already?
  804.         MOV    SI,CURSOR    ;Get position in file
  805.         JE    SCREEN_UP    ;If at bottom, then scroll up
  806.         CALL    FIND_NEXT    ;Find the start of next line
  807.         JC    DOWN_RET    ;If no more lines, then return
  808.         MOV    CURSOR,SI
  809.         INC    DH        ;Advance cursor to next row
  810.         CALL    SHIFT_RIGHT    ;Move cursor to current column
  811. DOWN_RET:
  812.         RET
  813. SCREEN_UP:
  814.         CMP    SI,LAST_CHAR    ;Get cursor offset
  815.         JE    DOWN_RET
  816.         CALL    FIND_START    ;Find the start of this line
  817.         MOV    CURSOR,SI    ;This is the new cursor
  818.         CALL    FIND_NEXT    ;Find the offset of next line
  819.         JC    SHIFT_RET    ;If no more lines then return
  820.         MOV    CURSOR,SI    ;This is the new cursor
  821.         MOV    SI,TOP_OF_SCREEN;Get the start of the top row
  822.         CALL    FIND_NEXT    ;And find the next line
  823.         MOV    TOP_OF_SCREEN,SI;Store the new top of screen
  824.         JMP    SHIFT_RET
  825. DOWN        ENDP
  826.  
  827. ;-----------------------------------------------------------------------
  828. ; These two routines move the screen one page at a time by calling the
  829. ; UP and DOWN procedures.
  830. ;-----------------------------------------------------------------------
  831. PGDN        PROC    NEAR
  832.         MOV    PAGE_PROC,OFFSET DOWN
  833. PAGE_UP_DN:
  834.         MOV    CL,ROWS        ;Get length of the screen
  835.         SUB    CL,5        ;Don't page a full screen
  836.         XOR    CH,CH        ;Make it a word
  837. PAGE_LOOP:
  838.         PUSH    CX
  839.         CALL    PAGE_PROC    ;Move the cursor down
  840.         POP    CX
  841.         LOOP    PAGE_LOOP    ;Loop for one page length
  842.         RET
  843. PGDN        ENDP
  844.  
  845. PGUP        PROC    NEAR
  846.         MOV    PAGE_PROC,OFFSET UP
  847.         JMP    PAGE_UP_DN
  848. PGUP        ENDP
  849.  
  850. ;-----------------------------------------------------------------------
  851. ; This toggles the insert/overstrike mode.
  852. ;-----------------------------------------------------------------------
  853. INSERT        PROC    NEAR
  854.         NOT    INSERT_MODE    ;Toggle the switch
  855.         JMP    REDO_PROMPT    ;Redraw the insert status
  856. INSERT        ENDP
  857.  
  858. ;-----------------------------------------------------------------------
  859. ; This deletes the character at the cursor by shifting the remaining 
  860. ; characters forward.
  861. ;-----------------------------------------------------------------------
  862. DEL_CHAR    PROC    NEAR
  863.         MOV    CX,LAST_CHAR
  864.         MOV    SI,CURSOR
  865.         MOV    DI,SI
  866.         CMP    SI,CX        ;Are we at end of file?
  867.         JAE    NO_DEL        ;If yes, then don't delete
  868.         LODSB
  869.         CALL    SAVE_CHAR    ;Save it for UNDO function
  870.         MOV    AH,[SI]        ;Look at the next character also
  871.         PUSH    AX        ;Save character were deleting
  872.         DEC    LAST_CHAR    ;Shorten the file by one
  873.         SUB    CX,SI
  874.         REP    MOVSB        ;Move file down one notch
  875.  
  876.         POP    AX        ;Get back character we deleted
  877.         CMP    AL,CR        ;Did we delete a CR?
  878.         JE    COMBINE
  879.         OR    DIRTY_BITS,4    ;Current line is dirty
  880. NO_DEL:
  881.         RET
  882. COMBINE:
  883.         CMP    AH,LF        ;Was the next character a LF?
  884.         JNE    NO_DEL_LF
  885.         CALL    DEL_CHAR    ;Now delete the line feed
  886. NO_DEL_LF:
  887.         CALL    DISPLAY_BOTTOM    ;Repaint bottom of the screen
  888.         MOV    DX,CUR_POSN
  889.         MOV    SAVE_COLUMN,DL    ;Save the cursor column
  890.         RET
  891. DEL_CHAR    ENDP
  892.  
  893. ;-----------------------------------------------------------------------
  894. ; This toggles the mark state and resets the paste buffer pointers.
  895. ;-----------------------------------------------------------------------
  896. MARK        PROC    NEAR
  897.         XOR    AX,AX
  898.         NOT    MARK_MODE    ;Toggle the mode flag
  899.         CMP    MARK_MODE,AL    ;Turning mode ON?
  900.         JNE    MARK_ON
  901.         MOV    DIRTY_BITS,1    ;Need to redraw the screen
  902.         MOV    MARK_START,0FFFFH
  903.         JMP    SHORT MARK_RET
  904. MARK_ON:
  905.         MOV    AX,CURSOR    ;Get the cursor offset
  906.         MOV    MARK_START,AX    ;Start of marked range
  907. MARK_RET:
  908.         MOV    MARK_END,  AX    ;End of marked range
  909.         MOV    MARK_HOME, AX    ;Center of marked range
  910.         RET
  911. MARK        ENDP
  912.  
  913. ;-----------------------------------------------------------------------
  914. ; This copies the marked to the paste buffer
  915. ;-----------------------------------------------------------------------
  916. COPY        PROC    NEAR
  917.         CMP    MARK_MODE,0    ;Is the mark mode on?
  918.         JE    COPY_END    ;If not, then do nothing
  919.         MOV    CX,MARK_END    ;Get end of mark region
  920.         MOV    SI,MARK_START    ;Get start of mark region
  921.         SUB    CX,SI        ;Number of bytes selected
  922.         MOV    PASTE_SIZE,CX
  923.         JCXZ    COPY_END
  924.         XOR    DI,DI        ;Point to paste bufferf
  925.  
  926.         PUSH    ES
  927.         MOV    ES,PASTE_SEG    ;Get the paste segment
  928.         REP    MOVSB        ;Put deleted text in buffer
  929.         POP    ES
  930.         CALL    MARK        ;This turns off select
  931. COPY_END:
  932.         RET
  933. COPY        ENDP
  934.  
  935. ;-----------------------------------------------------------------------
  936. ; This removes the marked text and places it in the paste buffer
  937. ;-----------------------------------------------------------------------
  938. CUT        PROC    NEAR
  939.         CMP    MARK_MODE,0    ;Is the mark mode on?
  940.         JE    NO_MARK        ;If not, then do nothing
  941.         MOV    CX,MARK_END    ;Get end of mark region
  942.         MOV    SI,MARK_START    ;Get start of mark region
  943.         SUB    CX,SI        ;Number of bytes selected
  944.         MOV    PASTE_SIZE,CX
  945.         JCXZ    NO_MARK
  946.         XOR    DI,DI        ;Point to paste bufferf
  947.  
  948.         PUSH    CX
  949.         PUSH    ES
  950.         MOV    ES,PASTE_SEG    ;Get the paste segment
  951.         REP    MOVSB        ;Put deleted text in buffer
  952.         POP    ES
  953.         POP    AX
  954.  
  955.         MOV    CX,LAST_CHAR
  956.         SUB    LAST_CHAR,AX    ;Shorten the file this much
  957.         MOV    DI,MARK_START
  958.         MOV    SI,MARK_END
  959.         SUB    CX,SI
  960.         JCXZ    NO_DELETE
  961.         REP    MOVSB        ;Shorten the file
  962. NO_DELETE:
  963.         MOV    DX,CUR_POSN
  964.         MOV    SI,MARK_START
  965.         CALL    LOCATE        ;Adjust the screen position
  966.         CALL    MARK        ;This turns off select
  967. NO_MARK:
  968.         RET
  969. CUT        ENDP
  970.  
  971. ;-----------------------------------------------------------------------
  972. ; This copies the paste buffer into the file at the cursor location
  973. ;-----------------------------------------------------------------------
  974. PASTE        PROC    NEAR
  975.         MOV    AX,PASTE_SIZE    ;Number of characters in buffer
  976.         OR    AX,AX        ;Any there?
  977.         JZ    NO_PASTE    ;If not, nothing to paste
  978.         MOV    SI,CURSOR    ;Get cursor location
  979.         PUSH    AX
  980.         PUSH    SI
  981.         CALL    OPEN_SPACE    ;Make room for new characters
  982.         POP    DI
  983.         POP    CX
  984.         JC    NO_PASTE    ;If no room, just exit
  985.         XOR    SI,SI        ;Point to paste buffer
  986.         PUSH    DS
  987.         MOV    DS,PASTE_SEG    ;Segment of paste buffer
  988.         REP    MOVSB        ;Copy in the new characters
  989.         POP    DS
  990.         MOV    SI,DI
  991.         MOV    CURSOR,SI    ;Cursor moved to end of insert
  992.         MOV    DX,CUR_POSN    ;Get current cursor row
  993.         CALL    LOCATE        ;Adjust the screen position
  994.         MOV    DIRTY_BITS,1    ;Redraw the screen
  995. NO_PASTE:
  996.         RET
  997. PASTE        ENDP
  998.  
  999. ;-----------------------------------------------------------------------
  1000. ; This prints the marked text.  If printer fails, it is canceled.
  1001. ;-----------------------------------------------------------------------
  1002. PRINT        PROC    NEAR
  1003.         CMP    MARK_MODE,0    ;Is mark mode on?
  1004.         JE    PRINT_RET    ;If not, nothing to print
  1005.         MOV    CX,MARK_END    ;End of marked region
  1006.         MOV    SI,MARK_START    ;Start of marked region
  1007.         SUB    CX,SI        ;Number of bytes selected
  1008.         JCXZ    PRINT_DONE    ;If nothing to print, return
  1009.  
  1010.         MOV    AH,2
  1011.         XOR    DX,DX        ;Select printer 0
  1012.         INT    17H        ;Get printer status
  1013.         TEST    AH,10000000B    ;Is busy bit set?
  1014.         JZ    PRINT_DONE
  1015.         TEST    AH,00100000B    ;Is printer out of paper?
  1016.         JNZ    PRINT_DONE
  1017. PRINT_LOOP:
  1018.         LODSB
  1019.         XOR    AH,AH
  1020.         INT    17H        ;Print the character
  1021.         ROR    AH,1        ;Check time out bit
  1022.         JC    PRINT_DONE    ;If set, quit printing
  1023.         LOOP    PRINT_LOOP
  1024.         MOV    AL,CR
  1025.         XOR    AH,0
  1026.         INT    17H        ;Finish with a CR
  1027. PRINT_DONE:
  1028.         CALL    MARK        ;Turn off the mark state
  1029. PRINT_RET:
  1030.         RET
  1031. PRINT        ENDP
  1032.  
  1033. ;-----------------------------------------------------------------------
  1034. ; This command restores any characters which have recently been deleted.
  1035. ;-----------------------------------------------------------------------
  1036. UNDO        PROC    NEAR
  1037.         XOR    AX,AX
  1038.         XCHG    AX,UNDO_LENGTH    ;Get buffer length
  1039.         MOV    SI,OFFSET UNDO_BUFFER
  1040.         JMP    INSERT_STRING
  1041. UNDO        ENDP
  1042.  
  1043. ;-----------------------------------------------------------------------
  1044. ; This inserts AX characters from CS:SI into the file.
  1045. ;-----------------------------------------------------------------------
  1046. INSERT_STRING    PROC    NEAR
  1047.         PUSH    SI        ;Save string buffer
  1048.         MOV    SI,CURSOR    ;Get cursor offset
  1049.         PUSH    AX        ;Save length of string
  1050.         PUSH    SI
  1051.         CALL    OPEN_SPACE    ;Make space to insert string
  1052.         POP    DI        ;Get back cursor position
  1053.         POP    CX        ;Get back string length
  1054.         POP    SI        ;Get back string buffer
  1055.         JC    NO_SPACE    ;If no space available, exit
  1056.  
  1057.         PUSH    DS
  1058.         PUSH    CS
  1059.         POP    DS
  1060.         ASSUME    DS:CSEG
  1061.         REP    MOVSB        ;Copy the characters in
  1062.         MOV    SI,CURSOR    ;Get the new cursor offset
  1063.         MOV    DX,CUR_POSN    ;Also get the current row
  1064.         MOV    DIRTY_BITS,1    ;And redraw the screen
  1065.         POP    DS
  1066.         ASSUME    DS:NOTHING
  1067.         CALL    LOCATE        ;Adjust the screen position
  1068. NO_SPACE:
  1069.         RET
  1070. INSERT_STRING    ENDP
  1071.  
  1072. ;-----------------------------------------------------------------------
  1073. ; This adds a character to the undo buffer.
  1074. ;-----------------------------------------------------------------------
  1075. SAVE_CHAR    PROC    NEAR
  1076.         MOV    BX,UNDO_LENGTH
  1077.         OR    BH,BH        ;Is buffer filled?
  1078.         JNZ    NO_SAVE
  1079.         INC    UNDO_LENGTH
  1080.         MOV    BYTE PTR CS:UNDO_BUFFER[BX],AL
  1081. NO_SAVE:
  1082.         RET
  1083. SAVE_CHAR    ENDP
  1084.  
  1085. ;-----------------------------------------------------------------------
  1086. ; This prompts for a verify keystroke then exits without saving the file
  1087. ;-----------------------------------------------------------------------
  1088. ABORT        PROC    NEAR
  1089.         ASSUME    DS:CSEG
  1090.         PUSH    CS
  1091.         POP    DS
  1092.         MOV    DH,ROWS        ;Last row on display
  1093.         INC    DH        ;Bottom row of screen
  1094.         XOR    DL,DL        ;First column
  1095.         MOV    SI,OFFSET VERIFY_MESS
  1096.         PUSH    CX
  1097.         CALL    TTY_STRING    ;Display verify message
  1098.         POP    CX
  1099.  
  1100.         XOR    AH,AH        ;Read the next key
  1101.         INT    16H        ;BIOS read key routine
  1102.         OR    AL,32        ;Convert to lower case
  1103.         CMP    AL,"y"        ;Was answer Yes?
  1104.         JE    TEST_CTRL_F2    ;If yes, then were finished
  1105. ABORT_RETURN:
  1106.         CALL    REDO_PROMPT    ;If not, redraw the prompt
  1107.         PUSH    ES
  1108.         POP    DS        ;Set DS back to file segment
  1109.         RET
  1110. TEST_CTRL_F2:
  1111.         CMP    CH,95        ;Is it CTRL F2
  1112.         JNE    FINISHED
  1113.         MOV    SI,NAME_POINTER
  1114.         MOV    BYTE PTR [SI],0    
  1115.         MOV    LAST_CHAR,0
  1116.         CALL    TOP
  1117.         JMP    ABORT_RETURN
  1118. FINISHED:
  1119.         MOV     AH,ORGATR
  1120.         MOV    NORMAL,AH    ;Go back to black and white
  1121.         MOV    DH,ROWS        ;Move to last row on screen
  1122.         XOR    DL,DL        ;And column zero
  1123.         CALL    SET_CURSOR
  1124.         INC    DH
  1125.         CALL    ERASE_EOL    ;Erase the last row
  1126. EXIT_TO_DOS:
  1127.         PUSH    CS
  1128.         POP    DS        ;Point to code segment
  1129.         MOV    AX,4C00H
  1130.         INT    21H
  1131.  
  1132. ABORT        ENDP
  1133.  
  1134. ;-----------------------------------------------------------------------
  1135. ;Prompt for a file name
  1136. ;-----------------------------------------------------------------------
  1137. FILENAME    PROC    NEAR
  1138.         MOV    P_FNAME_PROMPT,SI
  1139.         MOV    P_FNAME,AX
  1140.         MOV    SI,AX
  1141.         ADD    AX,55
  1142.         MOV    FNAME_LIMIT,AX
  1143. STRING_END_LOOP:
  1144.         MOV    AL,BYTE PTR[SI]
  1145.         INC    SI
  1146.         OR    AL,AL        ;At end of string yet?
  1147.         JNZ    STRING_END_LOOP
  1148.         DEC    SI
  1149.         MOV    P_FNAME_END,SI
  1150.         MOV    AX,CS
  1151.         MOV    DS,AX
  1152.         MOV    ES,AX
  1153.         ASSUME    DS:CSEG, ES:CSEG
  1154. NEXT_LETTER:
  1155.         MOV    DH,ROWS
  1156.         INC    DH        ;Last row on the screen
  1157.         XOR    DL,DL        ;First column
  1158.         MOV    SI,P_FNAME_PROMPT
  1159.         PUSH    DX
  1160.         CALL    TTY_STRING    ;Display a prompt
  1161.         POP    DX
  1162.         ADD    DL,11        ;Move right 11 spaces
  1163.         MOV    SI,P_FNAME
  1164.         CALL    TTY_STRING    ;Display the filename
  1165.  
  1166.         XOR    AH,AH        ;Read the next key
  1167.         INT    16H
  1168.         MOV    DI,P_FNAME_END    ;This points to last letter
  1169.         OR    AL,AL        ;Is it a real character?
  1170.         JZ    NEXT_LETTER    ;Ignore special keys
  1171.         CMP    AL,27        ;Is it escape?
  1172.         JNE    NOT_ESCAPE
  1173.         RET
  1174. NOT_ESCAPE:
  1175.         CMP    AL,CR        ;Is it CR?
  1176.         JE    GOT_NAME
  1177.         CMP    AL,8        ;Is it a backspace?
  1178.         JNE    NORMAL_LETTER
  1179.         CMP    DI,P_FNAME    ;At first letter?
  1180.         JLE    NEXT_LETTER    ;If yes, dont erase it
  1181.         MOV    BYTE PTR [DI-1],0
  1182.         DEC    P_FNAME_END
  1183.         JMP    NEXT_LETTER
  1184. NORMAL_LETTER:
  1185.         CMP    DI,FNAME_LIMIT    ;Too many letters?
  1186.         JG    NEXT_LETTER    ;If yes, ignore them
  1187.         XOR    AH,AH
  1188.         STOSW            ;Store the new letter
  1189.         INC    P_FNAME_END    ;Name is one character longer
  1190.         JMP    NEXT_LETTER    ;Read another keystroke
  1191. GOT_NAME:
  1192.         RET
  1193. FILENAME    ENDP
  1194. ;-----------------------------------------------------------------------
  1195. ; This prompts for a filename then writes the file.  The original file
  1196. ; is renamed to filename.BAK.  If an invalid filename is entered, the 
  1197. ; speaker is beeped. XXXXXXXXXXXXXXXX
  1198. ;-----------------------------------------------------------------------
  1199. EXIT        PROC    NEAR
  1200.         PUSH    DS
  1201.         PUSH    ES
  1202.         PUSH    CS
  1203.         POP    DS
  1204.         MOV    EXIT_MODE,0
  1205.         MOV    AX,NAME_POINTER
  1206.         MOV    SI,OFFSET ESAVE_MESS
  1207.         CMP    CH,100        ;Is it CTRL F7
  1208.         JNE    NOT_CTRL_F7
  1209.         MOV    SI,OFFSET SAVE_MESS
  1210.         MOV    EXIT_MODE,1
  1211. NOT_CTRL_F7:
  1212.         CMP    CH,98        ;Is it CTRL F5
  1213.         JNE    BEGIN_EXIT
  1214.         MOV    AX,P_MERGE_NAME
  1215.         MOV    SI,OFFSET COPY_MESS
  1216.         MOV    EXIT_MODE,2
  1217.         CMP    MARK_MODE,0
  1218.         JNE    BEGIN_EXIT
  1219.         JMP    ESCAPE
  1220.  
  1221. BEGIN_EXIT:
  1222.         CALL    FILENAME
  1223.  
  1224.         CMP    AL,27        ;Is it escape?
  1225.         JNE    EXIT_NOT_ESCAPE
  1226.         JMP    ESCAPE
  1227. EXIT_NOT_ESCAPE:
  1228.         MOV    DX,P_FNAME    ;Point to the filename
  1229.         MOV    AX,4300H    ;Get the files attribute
  1230.         INT    21H
  1231.         JNC    NAME_OK        ;If no error, filename is OK
  1232.         CMP    AX,3        ;Was it path not found error?
  1233.         JE    BAD_NAME    ;If yes, filename was bad
  1234. NAME_OK:
  1235.         MOV    SI,OFFSET DOT_$$$    ;Point to the ".$$$"
  1236.         MOV    DI,OFFSET NAME_DOT_$$$
  1237.         CALL    CHG_EXTENSION        ;Add the new extension
  1238.  
  1239.         MOV    DX,OFFSET NAME_DOT_$$$    ;Point to the temp filename
  1240.         MOV    AH,3CH            ;Function to create file
  1241.         MOV    CX,0020H        ;Attribute for new file
  1242.         INT    21H            ;Try to create the file
  1243.         JNC    NAME_WAS_OK        ;Continue if name was OK
  1244. BAD_NAME:
  1245.         MOV    AX,0E07H    ;Write a bell character
  1246.         INT    10H        ;BIOS tty service
  1247.         JMP    BEGIN_EXIT    ;Get another letter
  1248. WRITE_ERROR:
  1249.         MOV    AH,3EH        ;Close the file
  1250.         INT    21H
  1251.         JMP    BAD_NAME    ;Filename must be bad
  1252. NAME_WAS_OK:
  1253.         CMP    EXIT_MODE,2
  1254.         JNE    SKIP_SAVE_PASTE
  1255.         MOV    DX,MARK_START
  1256.         MOV    CX,MARK_END
  1257.         SUB    CX,DX
  1258.         JMP    SKIP_SAVE_FILE
  1259. SKIP_SAVE_PASTE:
  1260.         XOR    DX,DX        ;This is the file buffer
  1261.         MOV    CX,LAST_CHAR    ;Number of chars in file
  1262. SKIP_SAVE_FILE:
  1263.         MOV    DI,CX
  1264.         MOV    BX,AX        ;This is the handle
  1265.         MOV    AH,40H        ;Write to the file
  1266.         POP    DS        ;Recover buffer segment
  1267.         PUSH    DS
  1268.         INT    21H        ;Write the buffer contents
  1269.         POP    DS
  1270.         PUSH    DS
  1271.         JC    WRITE_ERROR    ;Exit on a write error
  1272.         CMP    AX,CX        ;Was entire file written?
  1273.         JNE    WRITE_ERROR    ;If not, exit
  1274.  
  1275.         PUSH    CS
  1276.         POP    DS        ;Get the code segment
  1277.         MOV    AH,3EH
  1278.         INT    21H            ;Close the temp file
  1279.         MOV    SI,OFFSET DOT_BAK    ;Point to the ".BAK"
  1280.         MOV    DI,OFFSET NAME_DOT_BAK
  1281.         CALL    CHG_EXTENSION        ;Make the backup filename
  1282.  
  1283.         MOV    DX,OFFSET NAME_DOT_BAK    ;Point to the backup name
  1284.         MOV    AH,41H
  1285.         INT    21H            ;Delete existing backup file
  1286.         MOV    DI,OFFSET NAME_DOT_BAK
  1287.         MOV    DX,P_FNAME
  1288.         MOV    AH,56H
  1289.         INT    21H
  1290.  
  1291.         MOV    DI,P_FNAME    ;Point to new filename
  1292.         MOV    DX,OFFSET NAME_DOT_$$$ ;Point to temporary file
  1293.         MOV    AH,56H        ;Rename temp to new file
  1294.         INT    21H        ;DOS function to rename
  1295.         CMP    CS:EXIT_MODE,2
  1296.         JNE    NOT_C_F5
  1297.         CALL    MARK
  1298. NOT_C_F5:
  1299.         CMP    CS:EXIT_MODE,1
  1300.         JNL    ESCAPE
  1301.         POP    AX        ;Restore the stack
  1302.         POP    AX
  1303.         JMP    FINISHED
  1304. ESCAPE:
  1305.         POP    ES        ;Get back file segments
  1306.         POP    DS
  1307.         MOV    CS:DIRTY_BITS,1    ;Redraw the screen
  1308.         CALL    REDO_PROMPT    ;Redraw the prompt
  1309.         RET
  1310. EXIT        ENDP
  1311.  
  1312. ;-----------------------------------------------------------------------
  1313. ; This subroutine displays a character by writing directly
  1314. ; to the screen buffer.  To avoid screen noise (snow) on the color
  1315. ; card, the horizontal retrace has to be monitored.
  1316. ;-----------------------------------------------------------------------
  1317. WRITE_INVERSE    PROC    NEAR
  1318.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1319.         MOV    BH,INVERSE    ;Attribute for inverse video
  1320.         JMP    SHORT WRITE_SCREEN
  1321. WRITE_NORMAL:
  1322.         MOV    BH,NORMAL    ;Attribute for normal video
  1323.         JMP    SHORT WRITE_SCREEN
  1324. WRITE_FIND:
  1325.         MOV    BH,SRCH_CLR    ;Attribute for find string
  1326. WRITE_SCREEN:
  1327.         MOV    BL,AL        ;Save the character
  1328.         PUSH    ES
  1329.         MOV    DX,STATUS_REG     ;Retrieve status register
  1330.         MOV    ES,VIDEO_SEG    ;Get segment of video buffer
  1331. HWAIT:
  1332.         IN    AL,DX        ;Get video status
  1333.         ROR    AL,1        ;Look at horizontal retrace
  1334.         JNC    HWAIT        ;Wait for retrace
  1335. WRITE_IT:
  1336.         MOV    AX,BX        ;Get the character/attribute
  1337.         STOSW            ;Write the character
  1338.         POP    ES
  1339.         RET
  1340. WRITE_INVERSE    ENDP
  1341.  
  1342. ;-----------------------------------------------------------------------
  1343. ; This moves the cursor to the row/column in DX.
  1344. ;-----------------------------------------------------------------------
  1345. SET_CURSOR    PROC    NEAR
  1346.         XOR    BH,BH        ;Were using page zero
  1347.         MOV    AH,2        ;BIOS set cursor function
  1348.         INT    10H
  1349.         RET
  1350. SET_CURSOR    ENDP
  1351.  
  1352. ;-----------------------------------------------------------------------
  1353. ; This computes the video buffer offset for the row/column in DX
  1354. ;----------------------------------------------------------------------
  1355. POSITION    PROC    NEAR
  1356.         MOV    AX,COLUMNS    ;Take columns per row
  1357.         MUL    DH        ;Times row number
  1358.         XOR    DH,DH
  1359.         ADD    AX,DX        ;Add in the column number
  1360.         SHL    AX,1        ;Times 2 for offset
  1361.         MOV    DI,AX        ;Return result in DI
  1362.         RET
  1363. POSITION    ENDP
  1364.  
  1365. ;-----------------------------------------------------------------------
  1366. ; This erases from the location in DX to the right edge of the screen
  1367. ;-----------------------------------------------------------------------
  1368. ERASE_EOL    PROC    NEAR
  1369.         CALL    POSITION    ;Find screen offset
  1370.         MOV    CX,COLUMNS    ;Get screen size
  1371.         SUB    CL,DL        ;Subtract current position
  1372.         JCXZ    NO_CLEAR
  1373. ERASE_LOOP:
  1374.         MOV    AL," "        ;Write blanks to erase
  1375.         CALL    WRITE_NORMAL    ;Display it
  1376.         LOOP    ERASE_LOOP
  1377. NO_CLEAR:    RET
  1378. ERASE_EOL    ENDP
  1379.  
  1380. ;-----------------------------------------------------------------------
  1381. ; This displays the function key prompt and insert mode state
  1382. ;-----------------------------------------------------------------------
  1383. REDO_PROMPT    PROC    NEAR
  1384.         ASSUME    DS:NOTHING, ES:NOTHING
  1385.         PUSH    DS
  1386.         PUSH    CS
  1387.         POP    DS
  1388.         ASSUME    DS:CSEG
  1389.         MOV    DH,ROWS        ;Put prompt at last row
  1390.         INC    DH
  1391.         XOR    DL,DL        ;And column 0
  1392.         CALL    POSITION    ;Convert to screen offset
  1393.         MOV    SI,OFFSET PROMPT_STRING
  1394. KEY_LOOP:
  1395.         MOV    AL,"F"        ;Display an "F"
  1396.         CALL    WRITE_NORMAL
  1397.         LODSB
  1398.         OR    AL,AL        ;Last key in prompt?
  1399.         JZ    PROMPT_DONE
  1400.         CALL    WRITE_NORMAL
  1401.  
  1402.         CMP    BYTE PTR CS:[SI],"0"    ;Is it F10?
  1403.         JNE    TEXT_LOOP
  1404.         LODSB
  1405.         CALL    WRITE_NORMAL
  1406. TEXT_LOOP:
  1407.         LODSB
  1408.         OR    AL,AL        ;Last letter in word?
  1409.         JNZ    WRITE_CHAR
  1410.  
  1411.         MOV    AL," "        ;Display a space
  1412.         CALL    WRITE_NORMAL
  1413.         JMP    KEY_LOOP
  1414. WRITE_CHAR:
  1415.         CALL    WRITE_INVERSE    ;Display the letter
  1416.         JMP    TEXT_LOOP    ;Do the next letter
  1417. PROMPT_DONE:
  1418.         MOV    DH,ROWS
  1419.         INC    DH        ;Get to last row on screen
  1420.         MOV    DL,PROMPT_LENGTH + 9
  1421.         CALL    ERASE_EOL    ;Erase to the end of this row
  1422.         MOV    AL,"O"        ;Write an "O"
  1423.         CMP    INSERT_MODE,0    ;In insert mode?
  1424.         JE    OVERSTRIKE
  1425.         MOV    AL,"I"        ;Write an "I"
  1426. OVERSTRIKE:
  1427.         DEC    DI        ;Backup one character position
  1428.         DEC    DI
  1429.         CALL    WRITE_NORMAL
  1430.         POP    DS
  1431.         RET
  1432. REDO_PROMPT    ENDP
  1433.  
  1434. ;-----------------------------------------------------------------------
  1435. ; This displays the file buffer on the screen.
  1436. ;-----------------------------------------------------------------------
  1437. DISPLAY_SCREEN    PROC    NEAR
  1438.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1439.         MOV    SI,TOP_OF_SCREEN;Point to first char on screen
  1440.         XOR    DH,DH        ;Start at first row
  1441.         JMP    SHORT NEXT_ROW
  1442. DISPLAY_BOTTOM:                ;This redraws the bottom only
  1443.         CALL    FIND_START    ;Find first character on this row
  1444.         MOV    DX,CUR_POSN    ;Get current cursor row
  1445. NEXT_ROW:
  1446.         PUSH    DX
  1447.         CALL    DISPLAY_LINE    ;Display a line
  1448.         POP    DX
  1449.         INC    DH        ;Move to the next row
  1450.         CMP    DH,ROWS        ;At end of screen yet?
  1451.         JBE    NEXT_ROW    ;Do all the rows
  1452.         RET
  1453. DISPLAY_SCREEN    ENDP
  1454.  
  1455. ;-----------------------------------------------------------------------
  1456. ; This subroutine displays a single line to the screen. DH holds the 
  1457. ; row number, SI has the offset into the file buffer. Tabs are expanded.
  1458. ; Adjustment is made for side shift.
  1459. ;-----------------------------------------------------------------------
  1460. DISPLAY_CURRENT    PROC    NEAR
  1461.         CALL    FIND_START
  1462.         MOV    DX,CUR_POSN
  1463. DISPLAY_LINE:
  1464.         XOR    DL,DL        ;Start at column zero
  1465.         MOV    MARGIN_COUNT,DL
  1466.         MOV    CX,DX        ;Use CL to count the columns
  1467.         CALL    POSITION    ;Compute offset into video
  1468. NEXT_CHAR:
  1469.         CMP    SI,LAST_CHAR    ;At end of file?
  1470.         JAE    LINE_DONE
  1471.         LODSB            ;Get next character
  1472.         CMP    AL,CR        ;Is it a carriage return?
  1473.         JE    FOUND_CR    ;Quit when a CR is found
  1474.         CMP    AL,TAB        ;Is this a Tab character
  1475.         JE    EXPAND_TAB    ;If yes, expand to spaces
  1476. DO_PUT:
  1477.         CALL    PUT_CHAR    ;Put character onto screen
  1478. TAB_DONE:
  1479.         CMP    CL,COLUMNSB    ;At right edge of screen?
  1480.         JB    NEXT_CHAR
  1481. LN_OVF:        CMP    BYTE PTR [SI],CR
  1482.         JNE    DO_DIA
  1483.         INC     SI
  1484.         CMP    SI,LAST_CHAR    ;At end of file?
  1485.         JAE    NOT_BEYOUND
  1486.         CMP    BYTE PTR [SI],LF;Is this the end of the line?
  1487.         DEC    SI
  1488.         JE    NOT_BEYOUND
  1489. DO_DIA:        DEC    DI        ;Backup one character
  1490.         DEC    DI
  1491.         MOV    AL,4        ;Show a diamond
  1492.         CALL    WRITE_INVERSE    ;In inverse video
  1493. NOT_BEYOUND:
  1494.         JMP    FIND_NEXT    ;Find start of next line
  1495. FOUND_CR:
  1496.         LODSB            ;Look at the next character
  1497.         CMP    AL,LF        ;Is it a line feed?
  1498.         JE    LINE_DONE
  1499.         MOV    AL,CR
  1500.         DEC    SI
  1501.         JMP    SHORT DO_PUT
  1502. LINE_DONE:
  1503.         MOV    DX,CX
  1504.         JMP    ERASE_EOL    ;Erase the rest of the line
  1505. EXPAND_TAB:
  1506.         MOV    AL," "        ;Convert Tabs to spaces
  1507.         CALL    PUT_CHAR
  1508.         MOV    AL,MARGIN_COUNT
  1509.         ADD    AL,CL
  1510.         TEST    AL,00000111B    ;At even multiple of eight?
  1511.         JNZ    EXPAND_TAB    ;If not keep adding spaces
  1512.         JMP    TAB_DONE
  1513. DISPLAY_CURRENT    ENDP
  1514.  
  1515. ;-----------------------------------------------------------------------
  1516. ; This displays a single character to the screen.  If the character is 
  1517. ; marked, it is shown in inverse video.  Characters outside the current
  1518. ; margin are not displayed. Characters left of the margin are skipped.
  1519. ;-----------------------------------------------------------------------
  1520. PUT_CHAR    PROC    NEAR
  1521.         MOV    BL,MARGIN_COUNT    ;Get distance to left margin
  1522.         CMP    BL,LEFT_MARGIN    ;Are we inside left margin?
  1523.         JAE    IN_WINDOW    ;If yes, show the character
  1524.         INC    BL
  1525.         MOV    MARGIN_COUNT,BL
  1526.         RET
  1527. IN_WINDOW:    CMP    SRCH_FLG,0
  1528.         JE    CKM
  1529.         CMP    SI,SRCH_BASE
  1530.         JBE    CKM
  1531.         CMP    SI,SRCH_END
  1532.         JA    CKM
  1533.         CALL    WRITE_FIND
  1534.         JMP    SHORT NEXT_COL
  1535. CKM:
  1536.         CMP    SI,MARK_START    ;Is this character marked?
  1537.         JBE    NOT_MARKED
  1538.         CMP    SI,MARK_END
  1539.         JA    NOT_MARKED
  1540.         CALL    WRITE_INVERSE    ;Marked characters shown inverse
  1541.         JMP    SHORT NEXT_COL
  1542. NOT_MARKED:
  1543.         CALL    WRITE_NORMAL
  1544. NEXT_COL:
  1545.         INC    CL        ;Increment the column count
  1546.         RET
  1547. PUT_CHAR    ENDP
  1548.  
  1549. ;-----------------------------------------------------------------------
  1550. ; This routine adds a character into the file.  In insert mode, remaining
  1551. ; characters are pushed forward. If a CR is inserted, a LF is added also.
  1552. ;-----------------------------------------------------------------------
  1553. INSERT_KEY    PROC    NEAR
  1554.         MOV    SI,CURSOR
  1555.         CMP    AL,CR        ;Was this a carriage return
  1556.         JNE    CK_INS
  1557.         CMP    AH,1CH
  1558.         JE    NEW_LINE
  1559. CK_INS:
  1560.         MOV    SI,CURSOR
  1561.         CMP    INSERT_MODE,0    ;In insert mode?
  1562.         JNE    INSERT_CHAR
  1563.         CMP    SI,LAST_CHAR    ;At end of file?
  1564.         JE    INSERT_CHAR
  1565.         CMP    BYTE PTR [SI],CR
  1566.         INC    SI
  1567.         CMP    SI,LAST_CHAR    ;At end of file?
  1568.         DEC    SI
  1569.         JE    INSERT_CHAR
  1570.         CMP    BYTE PTR [SI+1],LF;At end of line?
  1571.         JE    INSERT_CHAR
  1572.         MOV    DI,SI
  1573.         XCHG    DS:[SI],AL    ;Switch new character for old one
  1574.         CALL    SAVE_CHAR    ;Store the old character
  1575.         JMP    SHORT ADVANCE
  1576. INSERT_CHAR:
  1577.         PUSH    SI
  1578.         PUSH    AX        ;Save the new character
  1579.         MOV    AX,1
  1580.         CALL    OPEN_SPACE    ;Make room for it
  1581.         POP    AX        ;Get back the new character
  1582.         POP    DI
  1583.         JC    FILE_FULL
  1584.         STOSB            ;Insert character in file buffer
  1585. ADVANCE:
  1586.         OR    DIRTY_BITS,4    ;Current line is dirty
  1587.         PUSH    UNDO_LENGTH
  1588.         CALL    RIGHT        ;Move cursor to next letter
  1589.         POP    UNDO_LENGTH
  1590. FILE_FULL:
  1591.         RET
  1592. NEW_LINE:
  1593.         PUSH    SI
  1594.         MOV    AX,2
  1595.         CALL    OPEN_SPACE    ;Make space for CR and LF
  1596.         POP    DI        ;Get back old cursor location
  1597.         JC    FILE_FULL
  1598.         MOV    AX,LF*256+CR
  1599.         STOSW            ;Store the CR and LF
  1600.         CALL    DISPLAY_BOTTOM    ;Repaint bottom of the screen
  1601.         CALL    HOME        ;Cursor to start of line
  1602.         JMP    DOWN        ;Move down to the new line
  1603. INSERT_KEY    ENDP
  1604.  
  1605. ;-----------------------------------------------------------------------
  1606. ; This subroutine inserts spaces into the file buffer.  On entry AX
  1607. ; contains the number of spaces to be inserted.  On return, CF=1 if
  1608. ; there was not enough space in the file buffer.
  1609. ;-----------------------------------------------------------------------
  1610. OPEN_SPACE    PROC    NEAR
  1611.         MOV    CX,LAST_CHAR    ;Last character in the file
  1612.         MOV    SI,CX
  1613.         MOV    DI,CX
  1614.         ADD    DI,AX        ;Offset for new end of file
  1615.         JC    NO_ROOM        ;If no more room, return error
  1616.         MOV    LAST_CHAR,DI    ;Save offset of end of file
  1617.         SUB    CX,CURSOR    ;Number of characters to shift
  1618.         DEC    DI
  1619.         DEC    SI
  1620.         STD            ;String moves goes forward
  1621.         REP    MOVSB        ;Shift the file upward
  1622.         CLD
  1623.         CLC
  1624. NO_ROOM:
  1625.         RET
  1626. OPEN_SPACE    ENDP
  1627.  
  1628. ;-----------------------------------------------------------------------
  1629. ; This subroutine adjusts the cursor position ahead to the saved cursor
  1630. ; column.  On entry DH has the cursor row.
  1631. ;-----------------------------------------------------------------------
  1632. SHIFT_RIGHT    PROC    NEAR
  1633.         MOV    CL,SAVE_COLUMN    ;Keep the saved cursor offset
  1634.         XOR    CH,CH
  1635.         MOV    BP,CX        ;Keep the saved cursor position
  1636.         ADD    CL,LEFT_MARGIN    ;Shift into visable window also
  1637.         ADC    CH,0
  1638.         XOR    DL,DL
  1639.         MOV    CUR_POSN,DX    ;Get cursor row/column
  1640.         JCXZ    NO_CHANGE
  1641. RIGHT_AGAIN:
  1642.         PUSH    CX
  1643.         CMP    BYTE PTR [SI],CR;At end of line?
  1644.         JE    DONT_MOVE    ;If at end, stop moving
  1645.         CALL    RIGHT        ;Move right one character
  1646. DONT_MOVE:
  1647.         POP    CX
  1648.  
  1649.         MOV    AL,SAVE_COLUMN
  1650.         XOR    AH,AH
  1651.         CMP    AX,CX        ;Is cursor still in margin?
  1652.         JL    IN_MARGIN    ;If yes, keep moving
  1653.  
  1654.         MOV    DX,CUR_POSN    ;Get cursor column again
  1655.         XOR    DH,DH
  1656.         CMP    DX,BP        ;At saved cursor position?
  1657.         JE    RIGHT_DONE    ;If yes, were done
  1658.         JA    RIGHT_TOO_FAR    ;Did we go too far?
  1659. IN_MARGIN:
  1660.         LOOP    RIGHT_AGAIN
  1661. RIGHT_DONE:
  1662.         MOV    CX,BP
  1663.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  1664. NO_CHANGE:
  1665.         RET
  1666. RIGHT_TOO_FAR:
  1667.         CALL    LEFT        ;Move back left one place
  1668.         MOV    CX,BP
  1669.         MOV    SAVE_COLUMN,CL    ;Get back saved cursor position
  1670.         RET
  1671. SHIFT_RIGHT    ENDP
  1672.  
  1673. ;-----------------------------------------------------------------------
  1674. ; This subroutine skips past the CR and LF at SI.  SI returns new offset
  1675. ;-----------------------------------------------------------------------
  1676. SKIP_CR_LF    PROC    NEAR
  1677.         CMP    SI,LAST_CHAR    ;At last char in the file?
  1678.         JAE    NO_SKIP        ;If yes, dont skip anything
  1679.         CMP    BYTE PTR [SI],CR;Is first character a CR?
  1680.         JNE    NO_SKIP
  1681.         INC    SI        ;Look at next character
  1682.         CMP    SI,LAST_CHAR    ;Is it at the end of file?
  1683.         JAE    NO_SKIP        ;If yes, dont skip anymore
  1684.         CMP    BYTE PTR [SI],LF;Is next character a line feed?
  1685.         JNE    NO_SKIP        ;Skip any line feeds also
  1686.         INC    SI
  1687. NO_SKIP:
  1688.         RET
  1689. SKIP_CR_LF    ENDP
  1690.  
  1691. ;-----------------------------------------------------------------------
  1692. ; This subroutine finds the beginning of the previous line.
  1693. ;-----------------------------------------------------------------------
  1694. FIND_PREVIOUS    PROC    NEAR
  1695.         PUSH    CURSOR        ;Save the cursor location
  1696.         CALL    FIND_CR        ;Find start of this line
  1697.         MOV    CURSOR,SI    ;Save the new cursor
  1698.         CALL    FIND_START    ;Find the start of this line
  1699.         POP    CURSOR        ;Get back starting cursor
  1700.         RET
  1701. FIND_PREVIOUS    ENDP
  1702.  
  1703. ;-----------------------------------------------------------------------
  1704. ; This searches for the previous carriage return.  Search starts at SI.
  1705. ;-----------------------------------------------------------------------
  1706. FIND_CR        PROC    NEAR
  1707.         PUSH    CX
  1708.         MOV    AL,LF        ;Look for a carriage return
  1709.         MOV    DI,SI
  1710.         MOV    CX,SI
  1711.         JCXZ    AT_BEGINNING
  1712.         DEC    DI
  1713.         STD            ;Search backwards
  1714. LF_PREV:
  1715.         REPNE    SCASB        ;Scan for the character
  1716.         JCXZ    LF_END
  1717.         CMP    BYTE PTR [DI],CR
  1718.         JNE    LF_PREV
  1719.         DEC    DI
  1720. LF_END:
  1721.         CLD            ;Restore direction flag
  1722.         INC    DI
  1723.         MOV    SI,DI
  1724. AT_BEGINNING:
  1725.         POP    CX
  1726.         RET
  1727. FIND_CR        ENDP
  1728.  
  1729. ;-----------------------------------------------------------------------
  1730. ; This subroutine computes the location of the start of current line.
  1731. ; Returns SI pointing to the first character of the current line.
  1732. ;-----------------------------------------------------------------------
  1733. FIND_START    PROC    NEAR
  1734.         MOV    SI,CURSOR    ;Get the current cursor
  1735.         OR    SI,SI        ;At start of the file?
  1736.         JZ    AT_START    ;If yes, were done
  1737.         CALL    FIND_CR        ;Find the 
  1738.         CALL    SKIP_CR_LF
  1739. AT_START:
  1740.         RET
  1741. FIND_START    ENDP
  1742.  
  1743. ;-----------------------------------------------------------------------
  1744. ; This finds the offset of the start of the next line.  The search is 
  1745. ; started at location ES:SI.  On return CF=1 of no CR was found.
  1746. ;-----------------------------------------------------------------------
  1747. FIND_NEXT    PROC    NEAR
  1748.         PUSH    CX
  1749.         CALL    FIND_EOL    ;Find the end of this line
  1750.         JC    AT_NEXT        ;If at end of file, return
  1751.         CALL    SKIP_CR_LF    ;Skip past CR and LF
  1752.         CLC            ;Indicate end of line found
  1753. AT_NEXT:                  
  1754.         POP    CX
  1755.         RET
  1756. FIND_NEXT    ENDP
  1757.  
  1758. ;-----------------------------------------------------------------------
  1759. ; This searches for the next carriage return in the file.  The search
  1760. ; starts at the offset in register SI.
  1761. ;-----------------------------------------------------------------------
  1762. FIND_EOL    PROC    NEAR
  1763.         MOV    AL,CR        ;Look for a carriage return
  1764. CR_SCAN:
  1765.         MOV    CX,LAST_CHAR    ;Last letter in the file
  1766.         SUB    CX,SI        ;Count for the search
  1767.         MOV    DI,SI
  1768.         JCXZ    AT_END        ;If nothing to search, return
  1769.         REPNE    SCASB        ;Scan for the character
  1770.         MOV    SI,DI        ;Return the location of the CR
  1771.         JCXZ    AT_END        ;If not found, return
  1772.         CMP    BYTE PTR [SI],LF
  1773.         JNE    CR_SCAN
  1774.         DEC    SI
  1775.         CLC            ;Indicate the CR was found
  1776.         RET
  1777. AT_END:
  1778.         STC            ;Indicate CR was not found
  1779.         RET
  1780. FIND_EOL    ENDP
  1781.  
  1782. ;-----------------------------------------------------------------------
  1783. ; This subroutine positions the screen with the cursor at the row
  1784. ; selected in register DH.  On entry, SI holds the cursor offset.
  1785. ;-----------------------------------------------------------------------
  1786. LOCATE        PROC    NEAR
  1787.         MOV    CL,DH
  1788.         XOR    CH,CH
  1789.         MOV    CURSOR,SI
  1790.         XOR    DX,DX        ;Start at top of the screen
  1791.         OR    SI,SI        ;At start of buffer?
  1792.         JZ    LOCATE_FIRST
  1793.  
  1794.         CALL    FIND_START    ;Get start of this row
  1795.         XOR    DX,DX        ;Start at top of the screen
  1796.         OR    SI,SI        ;Is cursor at start of file?
  1797.         JZ    LOCATE_FIRST
  1798.         JCXZ    LOCATE_FIRST    ;If locating to top row were done
  1799. FIND_TOP:
  1800.         PUSH    SI
  1801.         PUSH    CX
  1802.         CALL    FIND_CR        ;Find previous row
  1803.         POP    CX
  1804.         POP    AX
  1805.         CMP    BYTE PTR [SI],CR
  1806.         JNE    LOCATE_FIRST
  1807.         CMP    BYTE PTR [SI+1],LF
  1808.         JNE    LOCATE_FIRST
  1809.         CMP    SI,AX        ;Did it change?
  1810.         JE    LOCATE_DONE    ;If not, quit moving
  1811.         INC    DH        ;Cursor moves to next row
  1812.         LOOP    FIND_TOP
  1813.  
  1814. LOCATE_DONE:
  1815.         PUSH    CURSOR
  1816.         MOV    CURSOR,SI
  1817.         CALL    FIND_START    ;Find start of top of screen
  1818.         POP    CURSOR
  1819. LOCATE_FIRST:
  1820.         MOV    TOP_OF_SCREEN,SI
  1821.         MOV    CUR_POSN,DX
  1822.         CALL    CURSOR_COL
  1823.         MOV    SAVE_COLUMN,DL
  1824.         RET
  1825. LOCATE        ENDP
  1826.  
  1827. ;-----------------------------------------------------------------------
  1828. ; This subroutine computes the correct column for the cursor.  No
  1829. ; inputs.  On exit, CUR_POSN is set and DX has the row/column.
  1830. ;-----------------------------------------------------------------------
  1831. CURSOR_COL    PROC    NEAR
  1832.         MOV    SI,CURSOR    ;Get cursor offset
  1833.         CALL    FIND_START    ;Find start of this line
  1834.         MOV    CX,CURSOR
  1835.         SUB    CX,SI
  1836.         MOV    DX,CUR_POSN    ;Get current row
  1837.         XOR    DL,DL        ;Start at column zero
  1838.         MOV    MARGIN_COUNT,DL    ;Count past the left margin
  1839.         JCXZ    COL_DONE
  1840. CURSOR_LOOP:
  1841.         LODSB            ;Get the next character
  1842.         CMP    AL,CR        ;Is it the end of line?
  1843.         JNE    NOT_EOL
  1844.         CMP    BYTE PTR [SI],LF
  1845.         JE    COL_DONE    ;If end, were done
  1846. NOT_EOL:
  1847.         CMP    AL,TAB        ;Is it a tab?
  1848.         JNE    NOT_A_TAB
  1849.  
  1850.         MOV    BL,MARGIN_COUNT
  1851.         OR    BL,00000111B
  1852.         MOV    MARGIN_COUNT,BL
  1853.         CMP    BL,LEFT_MARGIN    ;Inside visible window yet?
  1854.         JB    NOT_A_TAB    ;If not, don't advance cursor
  1855.         OR    DL,00000111B    ;Move to multiple of eight
  1856. NOT_A_TAB:
  1857.         MOV    BL,MARGIN_COUNT
  1858.         INC    BL
  1859.         MOV    MARGIN_COUNT,BL
  1860.         CMP    BL,LEFT_MARGIN
  1861.         JBE    OUT_OF_WINDOW
  1862.         INC    DL        ;Were at next column now
  1863. OUT_OF_WINDOW:
  1864.         LOOP    CURSOR_LOOP
  1865. COL_DONE:
  1866.         CMP    DL,COLUMNSB    ;Past end of display?
  1867.         JB    COLUMN_OK    ;If not, were OK?
  1868.         MOV    DL,COLUMNSB
  1869.         DEC    DL        ;Leave cursor at last column
  1870. COLUMN_OK:
  1871.         MOV    CUR_POSN,DX    ;Store the row/column
  1872.         RET
  1873. CURSOR_COL    ENDP
  1874.  
  1875. ;-----------------------------------------------------------------------
  1876. ; This displays the string at CS:SI at the location in DX.  The 
  1877. ; remainder of the row is erased.  Cursor is put at the end of the line.
  1878. ;-----------------------------------------------------------------------
  1879. TTY_STRING    PROC    NEAR
  1880.         ASSUME    DS:CSEG
  1881.         PUSH    DX
  1882.         CALL    POSITION    ;Compute offset into video
  1883.         POP    DX
  1884. TTY_LOOP:
  1885.         LODSB
  1886.         OR    AL,AL        ;At end of string yet?
  1887.         JZ    TTY_DONE
  1888.         INC    DL
  1889.         PUSH    DX
  1890.         CALL    WRITE_INVERSE    ;Write in inverse video
  1891.         POP    DX
  1892.         JMP    TTY_LOOP
  1893. TTY_DONE:
  1894.         CALL    SET_CURSOR    ;Move cursor to end of string
  1895.         JMP    ERASE_EOL    ;Erase the rest of line
  1896. TTY_STRING    ENDP
  1897.  
  1898. ;-----------------------------------------------------------------------
  1899. ; This copies the input filename to CS:DI and changes the extension
  1900. ;-----------------------------------------------------------------------
  1901. CHG_EXTENSION    PROC    NEAR
  1902.         ASSUME    DS:CSEG, ES:CSEG
  1903.  
  1904.         PUSH    SI
  1905.         MOV    SI,P_FNAME
  1906. CHG_LOOP:
  1907.         LODSB        
  1908.         CMP    AL,"."        ;Look for the extension
  1909.         JE    FOUND_DOT
  1910.         OR    AL,AL
  1911.         JZ    FOUND_DOT
  1912.         STOSB            ;Copy a character
  1913.         JMP    CHG_LOOP
  1914. FOUND_DOT:
  1915.         MOV    CX,5        ;Five chars in extension
  1916.         POP    SI
  1917.         REP    MOVSB        ;Move new extension in
  1918.         RET
  1919. CHG_EXTENSION    ENDP
  1920.  
  1921. ;-----------------------------------------------------------------------
  1922. ; This is the control break handler.  It ignores the break.
  1923. ;-----------------------------------------------------------------------
  1924. NEWINT23    PROC    FAR
  1925.         ASSUME    DS:NOTHING, ES:NOTHING
  1926.         MOV    CS:DIRTY_BITS,1
  1927.         CLC            ;Tell DOS to ignore break
  1928.         IRET
  1929. NEWINT23    ENDP
  1930.  
  1931. ;-----------------------------------------------------------------------
  1932. ; This is the severe error handler.  It homes the cursor before 
  1933. ; processing the error.
  1934. ;-----------------------------------------------------------------------
  1935. NEWINT24    PROC    FAR
  1936.         ASSUME    DS:NOTHING, ES:NOTHING
  1937.         PUSHF
  1938.         PUSH    AX
  1939.         PUSH    BX
  1940.         PUSH    DX
  1941.         MOV    CS:DIRTY_BITS,1
  1942.         XOR    DX,DX
  1943.         CALL    SET_CURSOR    ;Put cursor at home
  1944.         POP    DX
  1945.         POP    BX
  1946.         POP    AX
  1947.         POPF
  1948.         JMP    CS:OLDINT24
  1949. NEWINT24    ENDP
  1950. ;-----------------------------------------------------------------------
  1951. EVEN
  1952. NAME_DOT_$$$    EQU    $
  1953. NAME_DOT_BAK    EQU    $ + 80H
  1954. UNDO_BUFFER    EQU    $ + 100H
  1955. LINE_BUFFER    EQU    $ + 200H
  1956. NEW_STACK    EQU    $ + 500H
  1957. CSEG        ENDS
  1958. ;-----------------------------------------------------------------------
  1959. FILE_SEG    SEGMENT
  1960. FILE_SEG    ENDS
  1961. END        START
  1962.